﻿using System.Collections.ObjectModel;
using System.IO.Ports;
using System.Windows;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using HandyControl.Controls;
using Om.Camera;
using Om.Core.Extension;
using Om.Core.Singleton;
using Om.Ptz;
using OptoMeasure.Extension;
using TouchSocket.Core;
using TouchSocket.SerialPorts;
using TouchSocket.Sockets;

namespace OptoMeasure.Views;

public partial class DevicesConnectViewModel : ObservableObject
{
    public DevicesConnectViewModel()
    {
        InitViewData();
    }

    /// <summary>
    /// 相机列表
    /// </summary>
    public ObservableCollection<CameraConnectModel> CameraList { get; set; } = new ObservableCollection<CameraConnectModel> { };

    public ObservableCollection<string> ComPortList { get; set; } = new ObservableCollection<string>();

    public Visibility PtzVisibility => DevicesConfig.Instance.NeedPtz ==0 ? Visibility.Collapsed : Visibility.Visible;

    [RelayCommand]
    private async Task ConnectAllCamera()
    {
        try
        {
            await ConnectPtz();
        }
        catch (Exception e) { }

        foreach (var item in CameraList)
        {
            if(item.CameraInstance?.IsConnected == true) continue;
            try
            {
                await item.CameraInstance?.Connect(item.CurrentIdentifier);
            }
            catch (Exception e) { }
        }

    }
    [RelayCommand]
    private async Task DisConnectAllCamera()
    {
        await DisConnectPtz();
        foreach (var item in CameraList)
        {
            if (item.CameraInstance?.IsConnected != true) continue;
            try
            {
                await item.CameraInstance?.Disconnect();
            }
            catch (Exception e)
            {
            }
        }
    }

    #region PTZ

    [ObservableProperty] private bool _isPtzConnected;
    [ObservableProperty] private string _selectedCom4Ptz;
    [RelayCommand]
    private async Task ConnectPtz()
    {
        DevicesManager.Instance.Ptz.Client.Connected -= PtzConnected;
        DevicesManager.Instance.Ptz.Client.Connected += PtzConnected;
        await DevicesManager.Instance.Ptz.Connect(SelectedCom4Ptz);
        DevicesConfig.Instance.PtzCom = SelectedCom4Ptz;
    }

    private Task PtzConnected(ISerialPortClient client, ConnectedEventArgs e)
    {
        IsPtzConnected = true;
        return Task.CompletedTask;
    }

    [RelayCommand]
    private async Task DisConnectPtz()
    {
        DevicesManager.Instance.Ptz.Client.Closed -= PtzClosed;
        DevicesManager.Instance.Ptz.Client.Closed += PtzClosed;
        await DevicesManager.Instance.Ptz.Disconnect();
    }

    private Task PtzClosed(ISerialPortClient client, ClosedEventArgs e)
    {
        IsPtzConnected = false;
        return Task.CompletedTask;
    }

    #endregion


    #region 同步信号发生器

    [ObservableProperty] private bool _isSignalConnected;
    [ObservableProperty] private string _selectedCom4Signal;
    [RelayCommand]
    private async Task ConnectSignal()
    {
        DevicesManager.Instance.Signal.Client.Connected -= SignalConnected;
        DevicesManager.Instance.Signal.Client.Connected += SignalConnected;
        await DevicesManager.Instance.Signal.Connect(SelectedCom4Signal);
        DevicesConfig.Instance.SignalCom = SelectedCom4Signal;
    }

    private Task SignalConnected(ISerialPortClient client, ConnectedEventArgs e)
    {
        IsSignalConnected = true;
        return Task.CompletedTask;
    }

    [RelayCommand]
    private async Task DisConnectSignal()
    {
        DevicesManager.Instance.Signal.Client.Closed -= SignalClosed;
        DevicesManager.Instance.Signal.Client.Closed += SignalClosed;
        await DevicesManager.Instance.Signal.Disconnect();
    }

    private Task SignalClosed(ISerialPortClient client, ClosedEventArgs e)
    {
        IsSignalConnected = false;
        return Task.CompletedTask;
    }

    #endregion

    public void InitViewData()
    {
        ComPortList.Clear();
        var comPortNames = GetComPortNames();
        comPortNames.ToList().ForEach(a => ComPortList.Add(a));
        SelectedCom4Ptz = DevicesConfig.Instance.PtzCom;
        SelectedCom4Signal = DevicesConfig.Instance.SignalCom;
        IsPtzConnected = DevicesManager.Instance.Ptz.Client.Online;

        CameraList.Clear();
        var props = typeof(DevicesManager).GetProperties();
        foreach (var prop in props)
        {
            if(!typeof(IBaseCamera).IsAssignableFrom(prop.PropertyType))
                continue;

            var baseCamera = prop.GetValue(DevicesManager.Instance) as IBaseCamera;
            baseCamera.ConnectionChanged-= BaseCameraOnConnectionChanged;
            baseCamera.ConnectionChanged+= BaseCameraOnConnectionChanged;
            var itemCamera = new CameraConnectModel();
            itemCamera.CameraInstance = baseCamera;
            itemCamera.IsConnected = baseCamera.IsConnected;
            itemCamera.CameraDescription = prop.GetDescriptionOrName();
            itemCamera.CameraType = prop.Name;
            //itemCamera.CameraIdentifierList = new ObservableCollection<string>(await baseCamera.GetCameraList());
            itemCamera.CurrentIdentifier = DevicesConfig.Instance.CameraIds.ContainsKey(prop.Name)
                ? DevicesConfig.Instance.CameraIds[prop.Name]
                : "";
            CameraList.Add(itemCamera);

            //itemCamera.RefreshCameraIdentifierList();
        }
    }


    private void BaseCameraOnConnectionChanged(object? sender, bool e)
    {
        var camera = sender as IBaseCamera;
        var cvm = CameraList.FirstOrDefault(a => a.CurrentIdentifier == camera.Id);
        if(cvm == null) return;
        cvm.IsConnected = e;

        WeakReferenceMessenger.Default.Send(new object(), MsgToken.CameraConnectedChanged);
    }

    /// <summary>
    /// 获取可用串口列表
    /// </summary>
    /// <returns></returns>
    private string[] GetComPortNames()
    {
        string[] ports = SerialPort.GetPortNames();
        if (ports.Any())
            return ports
                .Select(a =>
                {
                    int.TryParse(a.Replace("COM", ""), out int num);
                    return new { Name = a, Num = num };
                })
                .OrderBy(a => a.Num)
                .Select(a => a.Name)
                .ToArray();
        else
            return new string[] { "暂无可用串口" };
    }
}

public partial class CameraConnectModel :ObservableObject
{
    /// <summary>
    /// 相机标识符（ip、Name）
    /// </summary>
    [ObservableProperty] private string _currentIdentifier;
    [ObservableProperty] private bool _isConnected;

    /// <summary>
    /// 相机描述
    /// </summary>
    public string CameraDescription { get; set; }
    /// <summary>
    /// 相机类型
    /// </summary>
    public string CameraType { get; set; }
    
    /// <summary>
    /// 相同类型的相机列表
    /// </summary>
    public ObservableCollection<string> CameraIdentifierList { get; set; } = new ObservableCollection<string>();

    public IBaseCamera CameraInstance { get; set; }
    [RelayCommand]
    private async Task Connect()
    {
        await CameraInstance.Connect(CurrentIdentifier);
        DevicesConfig.Instance.CameraIds[CameraType] = CurrentIdentifier;
    }
    [RelayCommand]
    private async Task DisConnect()
    {
        await CameraInstance.Disconnect();
    }

    /// <summary>
    /// 刷新相机列表
    /// </summary>
    /// <returns></returns>
    [RelayCommand]
    public async Task RefreshCameraIdentifierList()
    {
        var list = await CameraInstance.GetCameraList();
        CameraIdentifierList.Clear();
        list.ForEach(a => CameraIdentifierList.Add(a));
    }
}